/*******************************************************************************
 * Copyright 2017 osswangxining@163.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/
/**
 * Copyright © 2016-2017 The Thingsboard Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.iotp.infomgt.dao.sql.attributes;

import static org.iotp.infomgt.data.common.UUIDConverter.fromTimeUUID;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.iotp.infomgt.dao.DaoUtil;
import org.iotp.infomgt.dao.attributes.AttributesDao;
import org.iotp.infomgt.dao.model.sql.AttributeKvCompositeKey;
import org.iotp.infomgt.dao.model.sql.AttributeKvEntity;
import org.iotp.infomgt.dao.sql.JpaAbstractDaoListeningExecutorService;
import org.iotp.infomgt.dao.util.SqlDao;
import org.iotp.infomgt.data.common.UUIDConverter;
import org.iotp.infomgt.data.id.EntityId;
import org.iotp.infomgt.data.kv.AttributeKvEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
@SqlDao
public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService implements AttributesDao {

  @Autowired
  private AttributeKvRepository attributeKvRepository;

  @Override
  public ListenableFuture<Optional<AttributeKvEntry>> find(EntityId entityId, String attributeType,
      String attributeKey) {
    AttributeKvCompositeKey compositeKey = getAttributeKvCompositeKey(entityId, attributeType, attributeKey);
    return Futures.immediateFuture(Optional.ofNullable(DaoUtil.getData(attributeKvRepository.findOne(compositeKey))));
  }

  @Override
  public ListenableFuture<List<AttributeKvEntry>> find(EntityId entityId, String attributeType,
      Collection<String> attributeKeys) {
    List<AttributeKvCompositeKey> compositeKeys = attributeKeys.stream()
        .map(attributeKey -> getAttributeKvCompositeKey(entityId, attributeType, attributeKey))
        .collect(Collectors.toList());
    return Futures
        .immediateFuture(DaoUtil.convertDataList(Lists.newArrayList(attributeKvRepository.findAll(compositeKeys))));
  }

  @Override
  public ListenableFuture<List<AttributeKvEntry>> findAll(EntityId entityId, String attributeType) {
    return Futures.immediateFuture(
        DaoUtil.convertDataList(Lists.newArrayList(attributeKvRepository.findAllByEntityTypeAndEntityIdAndAttributeType(
            entityId.getEntityType(), UUIDConverter.fromTimeUUID(entityId.getId()), attributeType))));
  }

  @Override
  public ListenableFuture<Void> save(EntityId entityId, String attributeType, AttributeKvEntry attribute) {
    AttributeKvEntity entity = new AttributeKvEntity();
    entity.setEntityType(entityId.getEntityType());
    entity.setEntityId(fromTimeUUID(entityId.getId()));
    entity.setAttributeType(attributeType);
    entity.setAttributeKey(attribute.getKey());
    entity.setLastUpdateTs(attribute.getLastUpdateTs());
    entity.setStrValue(attribute.getStrValue().orElse(null));
    entity.setDoubleValue(attribute.getDoubleValue().orElse(null));
    entity.setLongValue(attribute.getLongValue().orElse(null));
    entity.setBooleanValue(attribute.getBooleanValue().orElse(null));
    return service.submit(() -> {
      attributeKvRepository.save(entity);
      return null;
    });
  }

  @Override
  public ListenableFuture<List<Void>> removeAll(EntityId entityId, String attributeType, List<String> keys) {
    List<AttributeKvEntity> entitiesToDelete = keys.stream().map(key -> {
      AttributeKvEntity entityToDelete = new AttributeKvEntity();
      entityToDelete.setEntityType(entityId.getEntityType());
      entityToDelete.setEntityId(fromTimeUUID(entityId.getId()));
      entityToDelete.setAttributeType(attributeType);
      entityToDelete.setAttributeKey(key);
      return entityToDelete;
    }).collect(Collectors.toList());

    return service.submit(() -> {
      attributeKvRepository.delete(entitiesToDelete);
      return null;
    });
  }

  private AttributeKvCompositeKey getAttributeKvCompositeKey(EntityId entityId, String attributeType,
      String attributeKey) {
    return new AttributeKvCompositeKey(entityId.getEntityType(), fromTimeUUID(entityId.getId()), attributeType,
        attributeKey);
  }
}
